package com.huawei.hwclouds.lubanops.demo.common.json;

import java.io.IOException;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.json.JsonSanitizer;
import com.huawei.hwclouds.lubanops.demo.common.constants.Constants;
import com.huawei.hwclouds.lubanops.demo.common.exception.common.JsonException;

/**
 * json处理的util类，这个类用于屏蔽底层json库的实现细节 <br>
 *
 * @author y00438022
 * @since 2020年2月29日
 */
public class JsonUtil {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    static {
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL); //空的字段不序列化
    }

    /**
     * 对象转成json字符串 <br>
     *
     * @param obj
     * @return
     * @author y00438022
     * @since 2020年2月29日
     */
    public static String toJSONString(Object obj) {
        String jsonString;
        try {
            jsonString = MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonException("failed change to json string", e);
        }
        return jsonString;
    }

    /**
     * 将json字符串转成java对象 <br>
     *
     * @param text
     * @param type
     * @return
     * @author y00438022
     * @since 2020年2月29日
     */
    public static <T> T parseObject(String text, Class<T> type) {
        try {
            text = JsonSanitizer.sanitize(text);
            return MAPPER.readValue(text, type);
        } catch (Exception e) {
            throw new JsonException("parse JSON exception:" + text, e);
        }
    }

    /**
     * 对于json字符串进行序列化
     *
     * @param text json的二进制字符串
     * @param type 转换的java类型
     * @param <T>  返回java类型
     * @return 反序列化的对象
     */
    public static <T> T parseObject(byte[] text, Class<T> type) {
        try {

            return MAPPER.readValue(text, type);
        } catch (Exception e) {
            throw new JsonException("parse JSON exception:" + new String(text, Constants.DEFAULT_CHARSET), e);
        }
    }

    /**
     * 对于json字符串进行序列化
     *
     * @param text   json 二进制字符串数组
     * @param offset 偏移量
     * @param length 长度
     * @param type   转换的java类型
     * @param <T>    java类型
     * @return 反序列化后的对象
     */
    public static <T> T parseObject(byte[] text, int offset, int length, Class<T> type) {
        try {
            return MAPPER.readValue(text, offset, length, type);
        } catch (Exception e) {
            throw new JsonException("parse JSON exception:" + new String(text, Constants.DEFAULT_CHARSET), e);
        }
    }

    public static <T> T parseObject(String text, TypeReference<T> type) {
        try {
            text = JsonSanitizer.sanitize(text);
            return MAPPER.readValue(text, type);
        } catch (Exception e) {
            throw new JsonException("parse JSON exception:" + text, e);
        }
    }

    public static <T> T parseObject(byte[] text, TypeReference<T> type) {
        try {
            return MAPPER.readValue(text, type);
        } catch (Exception e) {
            throw new JsonException("parse JSON exception:" + new String(text, Constants.DEFAULT_CHARSET), e);
        }
    }

    /**
     * <br>
     *
     * @param s
     * @param type
     * @return
     * @author y00438022
     * @since 2019年11月6日
     */
    public static <T> List<T> parseList(String s, Class<T> type) {
        try {
            s = JsonSanitizer.sanitize(s);
            return MAPPER.readValue(s, getListType(type));
        } catch (IOException e) {
            throw new JsonException("failed to parse:", e);
        }
    }

    private static JavaType getListType(Class<?> responseType) {
        return getCollectionType(MAPPER, List.class, responseType);
    }

    private static JavaType getCollectionType(ObjectMapper mapper, Class<?> collectionClass,
        Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

}
